Django - How to implement authentication service in microservices architecture - django

Basically, I have several independent services. I want to build a service for authentication. When client get a token from authentication service. Client use it for further request to others services. Client need to attach that token in header of request. The services receiving token need to verify the token by sending it to authentication server. So all requests that clients make to protected routes need to be verified by authentication service. The thing is I do not know the best place to put the code that automatically sends token to authentication service and receive the result.
Here is what i tried so far:
I implemented a middleware like that:
class VerifyTokenMiddleware(object):
def process_request(self, request):
if not request.META.get('HTTP_AUTHORIZATION'):
return HttpResponse(status=404)
auth_header = request.META.get('HTTP_AUTHORIZATION')
token = auth_header[4:]
response = requests.post(AUTH_URL, {"token": token})
if response.status_code == 400:
return HttpResponse(status=403)
return None
However, the problem of my solution is every requests to services(not auth service) have to pass through that middleware. Therefore, client cannot access unprotected routes like before.
Any help is extremely appreciated. :D
I used django restframework jwt https://github.com/GetBlimp/django-rest-framework-jwt.

It have many way to desiged microservice, you can write file restfull method like
class RestFulClient:
#classmethod
def get(cls, url, loggers, headers):
return is_success, status_code, data
#classmethod
def post(cls, url, headers, loggers, params={}):
return is_success, status_code, status_message, data
#classmethod
def put(cls, url, headers, loggers, params={}):
return is_success, status_code, status_message, data
#classmethod
def delete(cls, url, headers, loggers, params={}):
return is_success, status_code, status_message
Any question?

Related

How can I pass in a CSRF token with my API requests if I don't have a user login for my Django site?

Using the Django rest framework, I have an API endpoint I created that I call within my static files that I would like to pass a CSRF token into so that I'm the only one who can access the API.
My Django site does not have users with logins.
I essentially want to do something like this in my API endpoint:
#api_view(['POST'])
def payment(request, *args, **kwargs):
if (("Authorization" not in requests.headers) or (request.headers["Authorization"] != "token")):
return Response({"Error": "Not authorized for access."})
# ...
Do I need to generate a token one time and use that repeatedly?
Or can I generate one every time the script is used?
And how can I access this csrf token in my HTML file?
I'm using class-based views and I assume I would pass it in to get_context_data, but how would I set up the API endpoint to accept this CSRF token?
I would suggest to use TokenAuthentication right from the django-restframework:
https://www.django-rest-framework.org/api-guide/authentication/
You would then pass the token in the header of all your requests
like Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
If you use the decorators from the django-restframework, you can skipp all the custom token validation, as this is done by the django-restframework.
#api_view(['POST'])
#authentication_classes([TokenAuthentication])
#permission_classes([IsAuthenticated])
def payment(request, *args, **kwargs):
# ...

Flask-praetorian, not able to pass auth header to protected endpoint

im using flask-praetorian in order to add security to my app.
I got two routes: one for /login and a protected endpoint called /profile. The Login route works fine, it takes the username and password from the form, im able to pass the information to the guard object and authenticate it to get a new token, but im not been able to pass this token to the request headers for the protected endpoint.
I've tried to use the 'session" to add the header, the 'make_response' method, and the redirect(url_for()), but everytime it gets to the endpoint does it without the correct header causing the error.
Code below:
#user.route('/login', methods=['GET', 'POST'])
def login():
form = LoginForm()
if request.method == 'POST':
username = form.username.data
password = form.password.data
user = guard.authenticate(username, password)
token = guard.pack_header_for_user(user)
resp = make_response(profile())
resp.headers['Authorization'] = token['Authorization']
return resp
else:
return render_template('login.html', form=form)
#user.route('/profile')
#auth_required
def profile():
return render_template('profile.html')
(Author of the flask-praetorian package here)
The issue here is that you are just calling the profile() method from your login() method. Calling pack_header_for_user will not actually put the correct auth headers in the current request context. Instead, it just creates a header dict that could be put into a request (but is nicely returned as json). You could jam the token into the current request by tinkering with flask's request context, but it would not be the best way.
The right way to do this is to have your login route include the token in your response payload and then to make another call from your frontend code to the profile endpoint with the token added to the request header.
Really, I think you would be better off going with a different package like flask-security. The flask-praetorian package is intended to be used with pure APIs, and I haven't done any testing or prototyping with standard flask pages.

How to implement GUI Less Oauth Authentication system to access API's built using Python-Flask

I have written a simple Python Flask API which does operations like adding data to Database and getting data from Database, there is no UI for this API, Now I want to implement OAuth authentication system for this simple API, As there is NO GUI, I cant use google or FB Oauth Providers which redirects users to there login page.
In simple words, i want to create my own GUI less oauth Authentication system which secures my API as any user who wants to access my API should pass through this authentication system by passing access token in a header
I need Oauth Authentication system of my own for the API's below:
from flask import Flask, redirect, url_for, session
from flask import Flask,jsonify,request,make_response
from flask_login import login_user,logout_user,current_user,login_required,LoginManager,login_manager
from flask_oauth import OAuth
import json
from flask_mysqldb import MySQL
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_oauthlib.provider import OAuth1Provider
app = Flask(__name__)
class MYWIFI(db.Model):
__tablename__ = 'MYWIFI'
id = db.Column('id', db.Integer, primary_key=True)
data = db.Column('data', db.Unicode)
def __init__(self, id, data):
self.id = id
self.data = data
#app.route('/getall')
def getall():
access_token = get_access_token()
if access_token is None:
return redirect(url_for('login'))
else:
languages = [u.__dict__ for u in db.session.query(MYWIFI).all()]
for d in languages:
del d['_sa_instance_state']
print(languages)
languagesJSON = json.dumps(languages)
return languagesJSON
#app.route('/insert', methods=['GET','POST'])
def insert():
access_token = get_access_token()
if access_token is None:
return redirect(url_for('login'))
else:
if request.method == 'POST':
insert = request.get_json()
id = insert['id']
data = insert['data']
print id
print data
new = MYWIFI(id, data)
db.session.add(new)
db.session.commit()
return "Success"
def main():
app.run()
if __name__ == '__main__':
main()
Please can anyone help me in kick starting this
I appreciate for this help
If I understood correctly, what you want is to build API endpoints which are protected by OAuth 2.0 tokens. If that's the case you as the API builder does not have to worry how token obtaining process happens. The client that consumes your APIs must perform the token obtaining and pass them to your end.
About sending in headers, try to stick with standards already exist in the OAuth 2 domain. RFC6750 defines how to use tokens once a client obtains them. It defines bearer authentication schema to transmit access tokens. Check section 2.1 to how header is set.
GET /resource HTTP/1.1
Host: server.example.com
Authorization: Bearer mF_9.B5f-4.1JqM
Where mF_9.B5f-4.1JqM is the access token. Once your API receives a request, from your end you must validate the access token before granting access. For this there is RFC7662 which define the methodology to validate access token against the authorization server. See section 2 Introspection endpoint to get an understanding of it. Alternatively, access token can come in a JWT format thus allowing it to be self contained.
Unfortunately, I do not have code for proposed solutions. They will considerable amount of codes. But I suggest you to separate authorization logic from your code. That means validation of authorization must be a separate module in your python code. But below I give a suggestion with my python knowledge.
#app.route('/insert', methods=['GET','POST'])
def insert():
access_token = get_access_token()
# Auth Validation for insert - This is based on access tokens
# If token is invalid/not-present, exception is thrown with HTTP 401 - unauthorized
my_auth_module.validate_access_token(access_token)
if request.method == 'POST':
insert = request.get_json()
id = insert['id']
Also one final thing, your API should not worry about redirection for login. Let it be handled by your API client upon the 401 - Unathorized response.

Passing Token Using Fetch to a Django Rest API in React Native

I have my rest-api set up in Django and am using React Native to connect with it. I have registered users and am able to generate tokens however I am unable to pass the token in the header of the GET request. My code is as follows:
try{
let response = await fetch("http://127.0.0.1:8000/fishes/auth/",
{
method: 'GET',
headers: {
// 'Accept': 'application/json',
'Content-Type': 'application/json',
'Authorization': ' Token '+accessToken,
}});
let res = await response.text();
}}
I have been following this link http://cheng.logdown.com/posts/2015/10/27/how-to-use-django-rest-frameworks-token-based-authentication and have already verified that the response from the rest api is correct.
However on the phone with native react I get the following error in the console:
TypeError: Network request failed
at XMLHttpRequest.xhr.onerror (fetch.js:441)
at XMLHttpRequest.dispatchEvent (event-target.js:172)
at XMLHttpRequest.setReadyState (XMLHttpRequest.js:542)
What am I doing wrong in the GET code?
Alright 401 status code which means UnAuthorized.
For Django Rest Framework you must pass in the access Token as part of header for all your API requests.
Header Format will be
Key : Authorization
Value: Token <token>
You can see more here
http://www.django-rest-framework.org/api-guide/authentication/#tokenauthentication
I think that you need change
'Content-Type' to 'content-type'
On lowercase
See This answer.
The same-origin policy restricts the kinds of requests that a Web page can send to resources from another origin.
In the no-cors mode, the browser is limited to sending “simple” requests — those with safelisted methods and safelisted headers only.
To send a cross-origin request with headers like Authorization and X-My-Custom-Header, you have to drop the no-cors mode and support preflight requests (OPTIONS).
The distinction between “simple” and “non-simple” requests is for historical reasons. Web pages could always perform some cross-origin requests through various means (such as creating and submitting a form), so when Web browsers introduced a principled means of sending cross-origin requests (cross-origin resource sharing, or CORS), it was decided that such “simple” requests could be exempt from the preflight OPTIONS check.
I got around this issue by handling preflight request, as stated by the OP.
Previously, in my middleware, I filtered out requests that did not include an auth token and return 403 if they were trying to access private data. Now, I check for preflight and send a response allowing these types of headers. This way, when the following request comes (get, post, etc), it will have the desired headers and I can use my middleware as originally intended.
Here is my middleware:
class ValidateInflight(MiddlewareMixin):
def process_view(self, request, view_func, view_args, view_kwargs):
assert hasattr(request, 'user')
path = request.path.lstrip('/')
if path not in EXEMPT_URLS:
logger.info(path)
header_token = request.META.get('HTTP_AUTHORIZATION', None)
if header_token is not None:
try:
token = header_token
token_obj = Token.objects.get(token=token)
request.user = token_obj.user
except Token.DoesNotExist:
return HttpResponse(status=403)
elif request.method == 'OPTIONS':
pass
else:
return HttpResponse(status=403)
Here is my Options handling
class BaseView(View):
def options(self, request, *args, **kwargs):
res = super().options(request, *args, **kwargs)
res['Access-Control-Allow-Origin'] = '*'
res['Access-Control-Allow-Headers'] = '*'
return res

How to include user specific access to Django REST API in this example?

My understanding of authentication via an API is that the HTTP request sent by the client needs to include credentials, whether that be just a raw username and password (probably bad practice) or a hashed password, token, etc.
Normally in my Django views, I just use:
request.user.is_authenticated():
If I want my API to be used with an iOS app, this line of code cannot be used because it relies on sessions/cookies?
I would like to edit the following function, to allow it access to a specific user:
api_view(['GET'])
#csrf_exempt
def UserInfoAPI(request):
###if HTTP header includes name and password:###
private_info = Entry.objects.filter(user=request.user)
serializer = EntrySerializer(private_info, many=True)
return Response(serializer.data)
Is there a simple way to manually check for a username/pass in the HTTP header? I don't actually plan to use this in a production environment, but for the sake of understanding, I would like to understand how to have this function verify a username/pass from the http header.
Django REST Framework tries to determine the user that sends the request looking into the Authorization HTTP header. What you should send inside this header depends on the authentication scheme you choose. For example, if you choose BasicAuthentication, your header would be:
Authorization: Basic <"user:password" encoded in base64>
or, if you choose TokenAuthentication:
Authorization: Token <your token>
I would recommend the TokenAuthentication scheme. More schemes are listed in the docs.
To make sure only authenticated users have access to that API's endpoint, use the IsAuthenticated permission. This will check your user's credentials in the request, and if they are not correct, it will raise a HTTP 401 Unauthorized error.
Your Django REST Framework view would look something like this:
from rest_framework import generics
from rest_framework.permissions import IsAuthenticated
class UserInfo(generics.ListAPIView):
model = Entry
serializer_class = EntrySerializer
permission_classes = (IsAuthenticated,)
def get_queryset(self):
queryset = super(UserInfo, self).get_queryset()
user = self.request.user
return queryset.filter(user=user)
As for the code in your iOS app, this post may be helpful.