How to implement flask restplus authorizations - flask

I am trying to setup authentication in flask-restplus application. I want to add authentication to all endpoints in the application but don't want to write decorator on each route.
I am looking for apikey based authentication. The problem is, I am unable to identify how to intercept all requests and check for authentication token in the header.
Current Code:
authorization = {
'apikey': {
'type': 'apiKey',
'in': 'header',
'name': 'x-auth'
}
}
api = Api(
title='title',
version='1.0',
description="List of API's ",
validate=True,
authorizations=authorization,
security='apikey'
)
After doing the above steps, when I open swagger I can add token using the authorize button. But once the token is passed I am unable to intercept request & verify if token is correct or not.
Currently all the examples I could find, added another decorator on each route which I don't want as it leads to poor design & duplicate code.
Currently the closest example I got is :https://www.youtube.com/watch?v=xF30i_A6cRw&list=LLpaDwEA6bAAPZU5lz0ZRsuw&index=1
but it also uses decorator on each route.
So the problem statement is:
How to intercept all requests & check for correct token in there header without adding decorator on all routes

Very recently, I ran into a similar problem. But luckily we do have the Namespace that accepts a list of decorators, where in you can pass the custom decorator at Resource level, and it will be implemented by default to each method of that resource.
api = Namespace(
'some Name here',
description='some description',
security='apiKey',
authorizations = authorizations,
decorators= [token_required]
)
One point to note however, I had to just specify the security with each doc in the method, as under:
#api.doc('some operation', security = 'apiKey')
The beauty with this is that one click authorization flows to each method in the resource.

Related

#JWT_Required decorator Exception Handling

I am using an auth API using JWT and it works great.
This API is being used to authorize users for my web app. For this to work, I store JWT access_tokens as cookie manually with Flask.
I secure my resource with #JWT_required decorator and if I try to access a secure resource with a valid token everything works fine.
However, if the access token is missing or invalid/expired I get a JSON saying:
{
"message": "Missing cookie \"access_token_cookie\""
}
This is obvious the right message but rather then showing a JSON I want to redirect to the appropriate statuscode error page that is provided by Flask - in this case 401.
I have tried adding error handling for Flask and JWT Manager
Custom decorator, although I have played only poorly with this as I believe there has to be solution within FLASK-JWT-extended
#app.route('/dashbord')
#jwt_required
def dashbord():
return render_template('dashbord.html', title='Home')
My goal is to redirect to appropriate error page 404, 403, 401 if anything is wrong with the access token.
THE SOLUTION:
#jwt.unauthorized_loader
def my_invalid_token_callback(expired_token):
return render_template('401.html', title='Home')
Here's the solution Benjo posted at the bottom of his question:
#jwt.unauthorized_loader
def my_invalid_token_callback(expired_token):
return render_template('401.html', title='Home')
Here is the documentation for changing the results for invalid tokens: https://flask-jwt-extended.readthedocs.io/en/stable/changing_default_behavior.html#changing-callback-functions

How use segmented URL in AWS API Gateway?

I have a Lambda Function that it is accessible by an API Gateway. I can handle all POST and GET submitted requests to API endpoint (https://XXXXXXX.execute-api.us-east-1.amazonaws.com/default/myapi) inside my Lambda, but I need to use some segments at end of my URL when I am using PUT requests.
My Python code to call the API is here and it is working correctly:
import requests
import json
url = 'https://XXXXXXX.execute-api.us-east-1.amazonaws.com/default/myapi'
token = "my token"
data = {
"first_name": "Reza",
"birthday": "1986-09-12"
}
headers = {"Content-Type" : "application/json", "x-api-key":"MY_API_KEY"}
response = requests.put(url, data=json.dumps(data), headers=headers)
print(response.text)
But if I add users segment to end of the URL like this:
url = 'https://XXXXXXX.execute-api.us-east-1.amazonaws.com/default/myapi/users'
it will show this error:
{"message":"Missing Authentication Token"}
I need to add some static segments like users to return the list of all users and some dynamic segments like users/USER_ID (when USER_ID is a dynamic number) to return the information for a special user.
can you please guide me how I can use segmented URL in my AWS API Gateway?
The term you are using segmented URL might have caused your confusion. It is called path parameters with AWS. There is more than one way to do it. ANY+ integration is the easiest to handle.
Integrate with ANY+ integration to your lambda and you are good to go. All the path parameters will be delivered to your lambda.
http://www.1strategy.com/blog/2017/06/06/how-to-use-amazon-api-gateway-proxy/
Additional path parameter documentation,
https://docs.aws.amazon.com/apigateway/latest/developerguide/integrating-api-with-aws-services-lambda.html#api-as-lambda-proxy-expose-get-method-with-path-parameters-to-call-lambda-function
Good luck.

Manually validate flask-extended-jwt's access token

I have a SPA app that contains an form with an upload file field. I have a rest API whose endpoints are protected via flask-extended-jwt JWT. To authenticate the REST endpoints I use #jwt_required. I want to authenticate the upload request as well.
Because of the client side I can't add an Authorization Bearer header so I thought to add the access token as a hidden field when submitting the form.
What is the best way to manually validate the JWT access token after I read it from the form?
class Upload(Resource):
def post(self):
#TODO: check for access token
access_token = None
if 'access_token' in request.form and request.form['access_token']:
access_token = request.form['access_token']
else:
message = json.dumps({'message': 'Invalid or missing token', 'success': False})
return Response(response=message, status=401, mimetype='text/plain')
if access_token:
#TODO: validate_token(access_token)
Thank you
Author of flask-jwt-extended here. That's a great question. There is currently no supported way to do that in the extension, the grabbing the token from the request and decoding it are tightly coupled together. This would be hard to de-couple because there is a lot of conditional things that are going on when the full decode chain runs. For example, checking the CSRF value only if the request is sent in via a cookie, or differentiating between an access and refresh token for the sake of the blacklisting feature.
A generalized function could be created, it's signature would look something like decode_and_verify_jwt(encoded_token, is_access_token=True, check_csrf=False). However, this would complicate the rest of the code in flask_jwt_extended and be a rather confusing function to use for the general case.
I think in this case it would be easier just to add a fourth lookup in the extension, so you could use something like:
app.config['JWT_TOKEN_LOCATION'] = ['headers', 'forms']
app.config['JWT_FORM_KEY'] = 'access_token'
# Use the rest of the application normally
If you want to make a ticket on the github page so I can track this, I would be happy to work on it.

Django-social-auth google oauth token usage

I'm using Django-socila-auth plugin. It uses google API for Oauth 1.0 Authentication. Question is have anybody used it with google python API (gdata). I mean how to apply auth session_token, stored in django-social-auth model to my api call.
Can you help me with code to get this token from model and apply to gdata.PhotoService() instance. For now it is like this:
#getting model instance from django-social-auth model
association = Association.objects.get(user=request.user)
google_session_token=association.handle
google_secret=association.secret
#token string from django-social-auth
#model Association field "handle" looks like:
#google_session_token = '.......XG84PjwytqJkvr8WQhDxm1w-JplWK5zPndSHB13f.........'
gd_client = gdata.photos.service.PhotosService()
gd_client.debug = 'true'
gd_client.auth_token = google_session_token
#image.image is a file field, but problem not in this.
#it tries to send file in debug text.
#It just recieves 403 unauthorised callback.
photo = gd_client.InsertPhotoSimple(
'/data/feed/api/user/default/albumid/default', 'New Photo',
'Uploaded using the API', image.image, content_type='image/jpeg')
I'm recieving error
403 Invalid token string.
I understand that it needs secret too but how to apply it to API for auth?(To receive authorization to post photos.). BTW I added Picassa feed URL, as an option string for social-auth to ask permissions, so token I have asks for Picassa feed permissions when authorizing with google.
BTW. Google tutorial I've used is: here
I understand it's Oauth 1.0 rather than AusSub, but question is:
how to authenticate with token and secret I have and post a photo with this permission?
Just to answer my own problem. I used wrong way to do it, because problem in 'gd_client' and AuthSub.
It must check token on server. And it can not do it on localhost. You need to look ahead to Oauth/Oauth2 for better debugging and so on... No matter that it is much complex than AuthSub

Flash + pyAMF + Django session cookie security

First off, if there is a true, official way of having flash/flex's NetConnections usurp the session/cookie state of the surrounding web page, so that if the user has already logged in, they don't need to provide credentials again just to set up an AMF connection, please stop me now and post the official answer.
Barring that, I'm assuming there is not, as I have searched and it seems to not exist. I've concocted a means of doing this, but want some feedback as to whether it is secure.
Accessing a wrapper-page for a flash object will always go to secure https due to django middleware
When the page view is loaded in Django, it creates a "session alias" object with a unique key that points to the current session in play (in which someone ostensibly logged in)
That session alias model is saved, and that key is placed into a cookie whose key is another random string, call it randomcookie
That randomcookie key name is passed as a context variable and written into the html as a flashvar to the swf
The swf is also loaded only via https
The flash application uses ExternalInterface to call java to grab the value at that randomcookie location, and also deletes the cookie
It then creates a NetConnection to a secure server https location, passing that randomcookie as an argument (data, not in the url) to a login-using-cookie rpc
At the gateway side, pyamf looks up the session alias and gets the session it points to, and logs in the user based on that (and deletes the alias, so it can't be reused)
(And the gateway request could also set the session cookie and session.session_key to the known session ID, but I could let it make a whole new session key... I'm assuming that doing so should affect the response properly so that it contains the correct session key)
At this point, the returned cookie values on the flash side should stick to the NetConnection so that further calls are authenticated (if a connection is authenticated using username and password the normal way, this definitely works, so I think this is a safe bet, testing will soon prove or disprove this)
So, is this unsafe, or will this work properly? As far as I know, since the html page is guaranteed to be over ssl, the key and cookie data should be encrypted and not steal-able. Then, the info therein should be safe to use one-time as basically a temporary password, sent again over ssl because the gateway is also https. After that, it's using the normal pyAMF system over https and not doing anything out of the ordinary.
No responses on this so far, so the best I can do is confirm that it does in fact physically work. For details on how to set up Flex Builder to write html-wrappers that communicate with Django pages templates, see my other post. The above was accomplished using a combination of the aforementioned, plus:
Made a SessionAlias model:
class SessionAlias(models.Model):
alias = models.CharField( max_length=40, primary_key=True )
session = models.ForeignKey( Session )
created = models.DateTimeField( auto_now_add=True )
Flex points to a Django page that loads via a view containing:
s = SessionAlias()
s.alias = SessionStore().session_key // generates new 40-char random
s.session = Session.objects.get( session_key=request.session.session_key )
s.save();
randomcookie = SessionStore().session_key // generates new 40-char random
kwargs['extra_context']['randomcookie'] = randomcookie
response = direct_to_template( request, **kwargs )
response.set_cookie( randomcookie, value=alias )
In the flex html-wrapper, where randomcookie is the location to look for the alias:
<param name="flashVars" value="randomcookie={{randomcookie}}" />
In applicationComplete, where we get randomcookie and find the alias, and log on using that:
var randomcookie:String = this.parameters["randomcookie"];
// randomcookie is something like "abc123"
var js:String = "function get_cookie(){return document.cookie;}";
var cookies:String = ExternalInterface.call(js).toString();
// cookies looks like "abc123=def456; sessionid=ghi789; ..."
var alias:String = // strip out the "def456"
mynetconnection.call( "loginByAlias", alias, successFunc, failureFunc );
Which in turn access this pyamf gateway rpc:
from django.contrib.auth import SESSION_KEY, load_backend
from django.contrib.auth.models import User
from django.contrib import auth
from django.conf import settings
def loginByAlias( request, alias ):
a = SessionAlias.objects.get( alias=alias )
session_engine = __import__( settings.SESSION_ENGINE, {}, {}, [''] )
session_wrapper = session_engine.SessionStore( a.session.session_key )
user_id = session_wrapper.get( SESSION_KEY )
user = User.objects.get( id=user_id )
user.backend='django.contrib.auth.backends.ModelBackend'
auth.login( request, user )
a.delete()
return whateverToFlash
And at that point, on the flash/flex side, that particular mynetconnection retains the session cookie state that can make future calls such that, inside the gateway, request.user is the properly-authenticated user that logged onto the webpage in the first place.
Note again that the run/debug settings for flex must use https, as well as the gateway settings for NetConnection. And when releasing this, I have to make sure that authenticated users stay on https.
Any further info from people would be appreciated, especially if there's real feedback on the security aspects of this...
IE doesn't give access to cookies in local development but if you publish the SWF and put on a domain, it should pickup the session just like ever other browser. Use Firefox 3.6 to build your flex apps locally.
Tested in IE8, Firefox using a pyamf gateway on Flex 3 with NetConnection. The gateway function was decorated with #login_required